import multiprocessing
import time
import uuid

def processExecCallback(code, globals, local):
    print('processExecCallback')
    exec(code, globals, local)
    print('processExecCallback exec done:' + str(local))
    return local['r']

class ProcessExecutor:
    def __init__(self):
        self.process = None
        self.task_queue = multiprocessing.Queue()
        self.result_queue = multiprocessing.Queue()

    def exec(self, code, globals, local):
        return self.run_task(processExecCallback, code, globals, local)


    def run_task(self, task, arg1, arg2, arg3, timeout=10):
        # 如果没有子进程，或子进程已退出，创建并启动一个新的子进程
        if self.process is None or not self.process.is_alive():
            self.process = multiprocessing.Process(target=self.task_worker)
            self.process.start()

        # 生成唯一的任务ID
        task_uuid = uuid.uuid4()
        self.task_queue.put((task_uuid, task, arg1, arg2, arg3))

        start_time = time.time()
        while True:
            # 检查结果队列中是否有当前任务的结果
            if not self.result_queue.empty():
                result_uuid, result, error = self.result_queue.get()
                if result_uuid == task_uuid:
                    if error:
                        raise error
                    return result
            # 如果任务超时，终止子进程并抛出异常
            if time.time() - start_time > timeout:
                self.process.terminate()
                self.process = None
                raise TimeoutError("Task timed out")
            # 如果子进程意外退出，抛出异常
            if not self.process.is_alive():
                self.process = None
                raise Exception("Subprocess died unexpectedly")
            time.sleep(0.1)

    def task_worker(self):
        while True:
            g = self.task_queue.get()
            if g == None:
                break
            task_uuid, task, arg1, arg2, arg3 = g
            if task_uuid == 'quit' or task_uuid == None:
                break 
            try:
                result = task(arg1, arg2, arg3)
                self.result_queue.put((task_uuid, result, None))
            except Exception as e:
                self.result_queue.put((task_uuid, None, e))


    def quit(self):
        self.task_queue.put(None)
        if self.process != None :
            self.process.terminate()


def processExecCallback(code, globals, local):
    print('{} {} {}'.format(code, globals,local))
    return {'s': 'exec(code, globals, local)'}

if __name__ == '__main__':
    executor = ProcessExecutor()
    l = open('cell.py', 'r').read()
    local = {'s': l}
    r = executor.exec(l, local, 'r')
    print(r)
    r = executor.exec(r, local, 'r')
    print(r)

    print('quit')
    executor.quit()

